/* 
 * File:   BodyPart.h
 * Author: jcrada
 *
 * Created on December 15, 2008, 2:48 PM
 */

#ifndef _BODYPART_H
#define	_BODYPART_H

#include "defs.h"

#include <btBulletCollisionCommon.h>
#include <btBulletDynamicsCommon.h>
#include <string>
#include <QtXml/QDomDocument>
#include <QtXml/QDomElement>

namespace jcrada {

    class BodyPart {
    public:

        enum eShape {
            // -1           0       1
            S_NONE = -1, S_BOX, S_SPHERE,
            //    2         3               4
            S_CAPSULE_X, S_CAPSULE_Y, S_CAPSULE_Z,
            //    5         6      7
            S_CONE_X, S_CONE_Y, S_CONE_Z,
            //    8            9            10
            S_CYLINDER_X, S_CYLINDER_Y, S_CYLINDER_Z,
            //   11      12         13
            S_CAPSULE, S_CONE, S_CYLINDER,
        };

        enum eAxis {
            X_AXIS = 0, Y_AXIS, Z_AXIS,
        };
    private:
        int _id;
        int _parent_id;
        std::string _name;
        eShape _shape;
        eAxis _orientation;
        btScalar _size_x;
        btScalar _size_y;
        btScalar _size_z;
        btScalar _mass;
        btScalar _max_torque;

        btScalar _size_tolerance;

        btRigidBody* _rigid_body;
        btCollisionShape* _collision_shape;
        btMotionState* _motion_state;

    protected:

        virtual void setOrientation(eAxis orientation) {
            this->_orientation = orientation;
        }

    public:
        BodyPart();
        virtual ~BodyPart();

        virtual void set(const btTransform& at = btTransform::getIdentity());
        virtual void reset();

        virtual BodyPart* clone() const;

        static BodyPart* fromXml(const QDomElement& xml, bool* ok);
        void toXml(QDomDocument& xml, QDomElement* parent = NULL) const;
        virtual std::string toXml() const;

        virtual void setSizeX(const btScalar x);
        virtual btScalar getSizeX() const;

        virtual void setSizeY(const btScalar y);
        virtual btScalar getSizeY() const;

        virtual void setSizeZ(const btScalar z);
        virtual btScalar getSizeZ() const;

        virtual btScalar getSizeXt() const;
        virtual btScalar getSizeYt() const;
        virtual btScalar getSizeZt() const;
        virtual btScalar getSizeRt() const;

        virtual void scaleSizeAndMass(const btScalar factor);

        virtual btScalar getVolume() const;
        static btScalar GET_VOLUME(eShape shape, btScalar x, btScalar y, btScalar z, btScalar r);

        virtual void setId(int id) {
            this->_id = id;
        }

        virtual int getId() const {
            return this->_id;
        }

        virtual void setParentId(int id) {
            this->_parent_id = id;
        }

        virtual int getParentId() const {
            return this->_parent_id;
        }

        virtual bool isRoot() const {
            return this->_parent_id == -1;
        }

        virtual void setName(std::string name) {
            this->_name = name;
        }

        virtual std::string getName() const {
            return this->_name;
        }

        virtual void setShape(eShape shape) {
            this->_shape = shape;
            switch (shape) {
                case S_CAPSULE_X:
                case S_CONE_X:
                case S_CYLINDER_X:
                    setOrientation(X_AXIS);
                    break;
                case S_CAPSULE_Z:
                case S_CONE_Z:
                case S_CYLINDER_Z:
                    setOrientation(Z_AXIS);
                    break;
                case S_BOX:
                case S_SPHERE:
                case S_CAPSULE_Y:
                case S_CONE_Y:
                case S_CYLINDER_Y:
                    setOrientation(Y_AXIS);
                    break;
                default:
                    BDEBUG(TO_STRING(shape));
                    assert(0);
            }
        }

        virtual eShape getShape()const {
            return this->_shape;
        }

        virtual eShape getShapeWithoutOrientation() const {
            switch (getShape()) {
                case S_NONE: return S_NONE;
                case S_BOX: return S_BOX;
                case S_SPHERE: return S_SPHERE;
                case S_CAPSULE_X:
                case S_CAPSULE_Y:
                case S_CAPSULE_Z: return S_CAPSULE;
                case S_CONE_X:
                case S_CONE_Y:
                case S_CONE_Z: return S_CONE;
                case S_CYLINDER_X:
                case S_CYLINDER_Y:
                case S_CYLINDER_Z: return S_CYLINDER;
                default:
                    BDEBUG(TO_STRING(getShape()));
                    assert(0);
            }
        }

        virtual void setSize(const btScalar x, const btScalar y, const btScalar z) {
            setSizeX(x);
            setSizeY(y);
            setSizeZ(z);
        }

        virtual btScalar getSizeR() const {
            return getSizeX() / 2.0;
        }

        virtual void setMass(const btScalar mass) {
            this->_mass = mass;
        }

        virtual btScalar getMass() const {
            return this->_mass;
        }

        virtual void setMaxTorque(const btScalar torque) {
            this->_max_torque = torque;
        }

        virtual void addMaxTorque(const btScalar torque) {
            this->_max_torque += torque;
        }

        virtual btScalar getMaxTorque() const {
            return this->_max_torque;
        }

        virtual void setSizeTolerance(btScalar tolerance) {
            this->_size_tolerance = tolerance;
        }

        virtual btScalar getSizeTolerance() const {
            return this->_size_tolerance;
        }

        virtual eAxis getOrientation() const {
            return this->_orientation;
        }

        virtual void setRigidBody(btRigidBody* rb) {
            this->_rigid_body = rb;
        }

        virtual btRigidBody* getRigidBody() const {
            return this->_rigid_body;
        }

        virtual void setCollisionShape(btCollisionShape* shape) {
            this->_collision_shape = shape;
        }

        virtual btCollisionShape* getCollisionShape() const {
            return this->_collision_shape;
        }

        virtual void setMotionState(btMotionState* state) {
            this->_motion_state = state;
        }

        virtual btMotionState* getMotionState() const {
            return this->_motion_state;
        }
    };
}

#endif	/* _BODYPART_H */

